#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
##---------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##---------------------------------------------------------------------------##

import os
import collections


class Resource(collections.MutableMapping):

    def __new__(self, *args, **kwargs):
        resource_ = super().__new__(self) #*args, **kwargs)
        return resource_

    def __init__(self, **kwargs):
        self._defaults(kwargs, name='', filename='', basename='', absname='')
        kwargs.update({'index': -1, 'error': 0})
        self.__resource = {}
        self.__resource.update(kwargs)

    def _defaults(self, keywords, **kwargs):
        for k, v in list(kwargs.items()):
            keywords.setdefault(k, v)

    def __getitem__(self, key):
        """
        """
        return self.__resource[key]

    def __setitem__(self, key, value):
        """
        """
        if key not in self.__resource:
            raise KeyError
        self.__resource[key] = value

    def __delitem__(self, key):
        del self.__resource[key]

    def __iter__(self):
        return iter(self.__resource)

    def __len__(self):
        return len(self.__resource)

    def getSortKey(self):
        return self.__resource['name'].lower()


class ResourceManager(collections.Sequence):
    """
    ResourceManager(collections.Sequence)

    General resource manager to hold and query resources.
    """

    def __init__(self):
        self._key = -1
        self.__objects = []
        self._cache = {'name': {}, 'base': {}}
        self._sorted = {'name': []}

    def choice(self, index=None):
        if index is None:
            return self._key

        assert -1 < index < len(self.__objects)
        self._key = index

    def __len__(self):
        return len(self.__objects)

    def register(self, obj):
        assert isinstance(obj, Resource)
        if self._cache['name'].get(obj['name']):
            return
        assert obj['index'] == -1
        self._cache['name'][obj['name']] = obj
        if obj['filename']:
            obj['absname'] = os.path.abspath(obj['filename'])
            obj['basename'] = os.path.basename(obj['filename'])
            self._cache['name'][obj['basename']] = obj
        obj['index'] = len(self.__objects)
        self.__objects.append(obj)
        self._sorted = {'name': []}

    def __getitem__(self, index):
        if -1 < int(index) < len(self):
            return self.__objects[int(index)]  # int(index)%len(self)
        else:
            raise KeyError('Key must be between 0 and %s' % (len(self) - 1))

    def __contains__(self, value):
        return value in self._cache['name']

    @property
    def current(self):
        return None if self._key == -1 else self.__objects[self._key]

    def find(self, key, by="name"):
        if by.lower() in self._cache:
            value = self._cache[by.lower()].get(key, 0)
            if value is not None:
                return value
        elif by.lower() == 'all':
            return self.__objects

        raise ValueError

    def __iter__(self):
        return iter(self.__objects)

    def _do_sorting(self):
        self._sorted['name'] = self.__objects[:]
        self._sorted['name'].sort(key=lambda obj: obj['name'])

    def sort(self, name):
        if name in self._sorted:
            if not self._sorted[name]:
                self._do_sorting()
            return self._sorted[name]
        raise AttributeError

    def getAllSortedByName(self):
        if not self._sorted['name']:
            self._do_sorting()
        return self._sorted['name']

    def load(self, app, dirs, env, ext, src):
        import re
        Resource_Class = src
        ext_re = re.compile(ext, re.I | re.U)
        for path in SearchDirs(dirs):
            try:
                names = []
                if path and os.path.isdir(path):
                    names = [os.path.normcase(n) for n in os.listdir(path)]
                    names.sort()
                for name in names:
                    if not name or not ext_re.search(name):
                        continue
                    subpath = os.path.normpath(os.path.join(path, name))
                    if not os.path.isfile(subpath):
                        continue
                    obj = Resource_Class(dir_=subpath)
                    obj['filename'] = subpath
                    obj['name'] = ext_re.sub("", name.strip()).replace('_', ' ')
                    self.register(obj)
            except EnvironmentError:
                pass


def SearchDirs(dirs, env=None):
    """
    SearchDirs(dirs:list, env=None:string) -> None

    Yield available paths as environment value and dirs values are iterated.
    """
    from .utillib.pathdb import PATH_DB, NJ_PATH

    if env and env in os.environ:
        s_dir = []
        for path in (os.normpath(p)
                     for p in os.environ.get(env).split(os.pathsep)):
            if path and os.path.isdir(path):
                yield path

    d_dict = PATH_DB.dn
    for path in (d_dict['config'], d_dict['data'], d_dict['maint']):
        for subpath in (NJ_PATH([path, s]) for s in dirs):
            if subpath and os.path.isdir(subpath):
                if subpath.endswith("-*"):
                    for subsubpath in (OJ_PATH([subpath, ss])
                                        for ss in os.listdir(subpath)):
                        if subsubpath and os.path.isdir(subsubpath):
                            yield subsubpath
                else:
                    yield subpath


class Tile(Resource):
    """
    Tile resource detail for a game canvas backround image.
    """

    def __init__(self, **kwargs):
        """
        Initialize a tile resource with it details. Call next method in order
        with parameters.

        .. \__init__([color:int=None, dir_:text]):

        *Parameters*:
          ``color`` : {text} None
          ``stretch`` : {bool} False
            Set True when ``dir_`` of image is *stretch.
          ``save_aspect`` : {bool} False
            Set True when ``dir_`` of image is *save-aspect*.
          ``dir_`` : {text} None
            Used to set ``stretch`` and ``save_aspect`` then deleted.
        """
        kwargs.setdefault('color', None)
        kwargs['stretch'] = False
        kwargs['save_aspect'] = False
        if 'dir_' in kwargs:
            if os.path.split(kwargs['dir_'])[-1] == 'stretch':
                kw['stretch'] = True
            if os.path.split(kwargs['dir_'])[-1] == 'save-aspect':
                kwargs['stretch'] = True
                kwargs['save_aspect'] = True
            del kwargs['dir_']
        super(Tile, self).__init__(**kwargs)


class Sample(Resource):
    """
    Sample Resource for a game soundeffect.
    """

    def __init__(self, **kwargs):
        """
        Initialize a sundd resource with it details. Call next method in order
        with parameters.

        .. \__init__([sound:int=-1, dir_:text]):

        *Parameters*:
          ``volume`` : {int} -1
          ``dir_`` : {text} None
            Deleted.
        """
        kwargs['volume'] = -1
        if 'dir_' in kwargs:
            del kwargs['dir_']
        super(Sample, self).__init__(**kwargs)


TILE_DB = ResourceManager()
SOUND_DB = ResourceManager()